package com.mpsc.multi.source.config.datasource;

import com.mpsc.api.bean.RoleInfoEntity;
import com.mpsc.api.config.util.SpringContextUtil;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 多数据源配置类
 */
@Configuration
//@EnableTransactionManagement
public class DataSourceConfig {

    private static final String datasourcePrefix = "spring.datasource.";
    private static final String multiSourceRule = "spring.rule";

    static Map<String, AbstractBeanDefinition> datasMap = new HashMap();

    private static int max;

    private static int min;

    private static String dbPrefix;

    @Autowired
    private Environment environment;

    @Value("${spring.rule}")
    private String datasourceRule;
    @Autowired
    public ApplicationContext applicationContext;

    /**
     * 动态数据源: 读取配置文件，将数据源动态的放入到数据库中
     *
     * @return
     */
    @Primary
    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource() {
        ConfigurableApplicationContext configurableApplicationContext = (AbstractApplicationContext) applicationContext;
            // 获取bean工厂并转换为DefaultListableBeanFactory
            DefaultListableBeanFactory defaultListableBeanFactory =
                    (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        //获取分库规则
        getDatasourceMaxAndMin();
        //数据库基本信息配置
        String driverClassName;
        String jdbcUrl;
        String username;
        String password;
        // 配置多数据源
        Map<Object, Object> dsMap = new HashMap();
        HikariConfig hikariConfig;
        HikariDataSource hikariDataSource;
        BeanDefinitionBuilder beanDefinitionBuilder;
        AbstractBeanDefinition rawBeanDefinition;
        for (int i = min; i <= max; i++) {
            driverClassName = environment.getProperty(datasourcePrefix + dbPrefix + i + ".driver-class-name");
            jdbcUrl = environment.getProperty(datasourcePrefix + dbPrefix + i + ".jdbc-url");
            username = environment.getProperty(datasourcePrefix + dbPrefix + i + ".username");
            password = environment.getProperty(datasourcePrefix + dbPrefix + i + ".password");
            //创建数据源
            hikariConfig = new HikariConfig();
            hikariConfig.setDriverClassName(driverClassName);
            hikariConfig.setJdbcUrl(jdbcUrl);
            hikariConfig.setUsername(username);
            hikariConfig.setPassword(password);
            hikariDataSource = new HikariDataSource(hikariConfig);
            if (min == i) {
                //设置默认数据源
                dynamicDataSource.setDefaultTargetDataSource(hikariDataSource);
            }
            // 注册bean
            dsMap.put(dbPrefix + i, hikariDataSource);
            beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(HikariDataSource.class);
            rawBeanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
            rawBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(hikariConfig);
            defaultListableBeanFactory.registerBeanDefinition(dbPrefix + i, beanDefinitionBuilder.getBeanDefinition());
            //datasMap.put(dbPrefix + i, rawBeanDefinition);
        }
        dynamicDataSource.setTargetDataSources(dsMap);
        return dynamicDataSource;
    }

    public static void injectionContainer() {
        //将applicationContext转换为ConfigurableApplicationContext
        ConfigurableApplicationContext configurableApplicationContext =
                (ConfigurableApplicationContext) SpringContextUtil.getApplicationContext();
        // 获取bean工厂并转换为DefaultListableBeanFactory
        DefaultListableBeanFactory defaultListableBeanFactory =
                (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
//        if (CollectionUtils.isNotEmpty(Collections.singleton(datasMap))) {
//            for(String dbname: datasMap.keySet()){
////                BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(HikariDataSource.class);
////                AbstractBeanDefinition rawBeanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
////                rawBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(datasMap.get(dbname));
//                defaultListableBeanFactory.registerBeanDefinition(dbname, datasMap.get(dbname));
//            }
//        }
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(RoleInfoEntity.class);
        beanDefinitionBuilder.addPropertyValue("id", "1");
        defaultListableBeanFactory.registerBeanDefinition("dbname", beanDefinitionBuilder.getBeanDefinition());

        Object obj = SpringContextUtil.getBean("dbname");
        System.out.println(obj);
    }

    /**
     * 获取分库rule，计算分库
     * db->${1..2}
     */
    private boolean getDatasourceMaxAndMin() {
        //String datasourceRule = environment.getProperty(multiSourceRule);
        if (StringUtils.isNotEmpty(datasourceRule)) {
            String[] rules = datasourceRule.split("->");
            dbPrefix = rules[0];
            String rulesNum = rules[1].substring(1, rules[1].length() - 1);
            String[] dataNum = rulesNum.split("-");
            min = Integer.parseInt(dataNum[0]);
            max = Integer.parseInt(dataNum[1]);
            if (min > max) {
                int t = max;
                max = min;
                min = t;
            }
        } else {
            throw new RuntimeException("缺少数据库分片spring.rule配置");
        }
        return true;
    }


//    //数据源1
//    @Bean(name = "db1")
//    //@ConfigurationProperties(prefix = "multi.datasource.db1") // application.properteis中对应属性的前缀
//    public DataSource dataSource1() {
//        HikariConfig hikariConfig=new HikariConfig();
//        hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/sharding_2?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
//        hikariConfig.setUsername("root");
//        hikariConfig.setPassword("123456");
//        hikariConfig.setDriverClassName("com.mysql.jdbc.Driver");
//        HikariDataSource hikariDataSource=new HikariDataSource(hikariConfig);
//        return hikariDataSource;
//        //return DataSourceBuilder.create().build();
//    }
//
//    //数据源2
//   @Bean(name = "datasource2")
//    //@ConfigurationProperties(prefix = "spring.datasource.db2") // application.properteis中对应属性的前缀
//    public DataSource dataSource2() {
//        HikariConfig hikariConfig=new HikariConfig();
//        hikariConfig.setJdbcUrl("jdbc:mysql://localhost:3306/sharding_1?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC");
//        hikariConfig.setUsername("root");
//        hikariConfig.setPassword("123456");
//        hikariConfig.setDriverClassName("com.mysql.jdbc.Driver");
//        HikariDataSource hikariDataSource=new HikariDataSource(hikariConfig);
//        return hikariDataSource;
//        //return DataSourceBuilder.create().build();
//    }

    /**
     * 动态数据源
     *
     * @return
     */
//    @Primary
//    @Bean(name = "dynamicDataSource")
//    public DataSource dynamicDataSource() {
//        DynamicDataSource dynamicDataSource = new DynamicDataSource();
//        // 默认数据源
//        dynamicDataSource.setDefaultTargetDataSource(dataSource1());
//        // 配置多数据源
//        Map<Object, Object> dsMap = new HashMap();
//        dsMap.put("db1", dataSource1());
//        dsMap.put("datasource2", dataSource2());
//        dynamicDataSource.setTargetDataSources(dsMap);
//        return dynamicDataSource;
//    }

//    @Bean("sqlSessionFactory")
//    public SqlSessionFactory sqlSessionFactory() throws Exception {
//        SqlSessionFactoryBean sqlSessionFactory = new SqlSessionFactoryBean();
//        sqlSessionFactory.setDataSource(dynamicDataSource());
//        // 使用自定义的多数据源事务工厂，如采用JdbcTemplate方式可不配置
//        sqlSessionFactory.setTransactionFactory(new MultiDataSourceTransactionFactory());
//        //添加XML目录
//        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
//        //sqlSessionFactory.setConfigLocation(resolver.getResource("classpath:mybatis-config.xml"));
//        sqlSessionFactory.setMapperLocations(resolver.getResources("classpath*:com/mpsc/multi/source/mapper/*.xml"));
//        return sqlSessionFactory.getObject();
//    }

//    @Bean
//    public DataSource multipleDataSource(@Qualifier("datasource1") DataSource dataSource1,
//                                         @Qualifier("datasource2") DataSource dataSource2) {
//        DynamicDataSource dynamicDataSource = new DynamicDataSource();
//        Map<Object, Object> targetDataSources = new HashMap<>();
//        targetDataSources.put("dataSource1", dataSource1);
//        targetDataSources.put("dataSource2", dataSource2);
//        dynamicDataSource.setTargetDataSources(targetDataSources);
//        dynamicDataSource.setDefaultTargetDataSource(dataSource1);
//        return dynamicDataSource;
//    }


    /**
     * 配置@Transactional注解事物
     *
     * @return
     */
    // @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
}
